iT邦幫忙

2023 iThome 鐵人賽

DAY 25
0
Software Development

開心撰寫 PHPUnit系列 第 25

Day 25. 兩個物件互動測試 - Mock

  • 分享至 

  • xImage
  •  

這一篇我們就來討論 PttCrawler 如何進行測試,首頁我們先來看看我們目前『可能』的程式碼

<?php
// src/PttCrawler.php

namespace Recca0120\Ithome30;

use Psr\Http\Client\ClientInterface;
use Recca0120\Ithome30\Crawlers\Home;
use Recca0120\Ithome30\Crawlers\Board;

class PttCrawler
{
    public function __construct(private ClientInterface $httpClient)
    {
    }

    public function all()
    {
        $crawler = new Home($this->httpClient);
        $boardCrawler = new Board($this->httpClient);

        $results = [];
        foreach ($crawler->all() as $board) {
            foreach ($boardCrawler->fetch($board) as $articles) {
                $results[] = $articles;
            }
        }

        return $results;
    }
}

在 construct 是注入一個 ClientInterface,在 method all 即是 new Home 及 new Board 這兩個物件,這樣我們想要用 Mock 來模擬回傳值會變的非常的不容易,所以我們可以先把程式碼調整為

<?php
// src/PttCrawler.php

namespace Recca0120\Ithome30;

use Recca0120\Ithome30\Crawlers\Home;
use Recca0120\Ithome30\Crawlers\Board;

class PttCrawler
{
    public function __construct(private Home $home, private Board $board)
    {
    }

    public function all()
    {
        $results = [];
        foreach ($this->home->all() as $board) {
            foreach ($this->board->fetch($board) as $articles) {
                $results[] = $articles;
            }
        }

        return $results;
    }
}

construct 改為注入 Home, Board,這樣我們就可以直接針對 Home 及 Board 來進行 mock 後,再注入到 PttCrawler 了。

這時候我們可以先打開 HomeTest 觀察 all 的回傳值,及打開 BoardTest 的回傳值,立刻就可以模擬出 Home 及 Board 的回傳資料,我們就可以寫出以下的測試程式碼

<?php

namespace Recca0120\Ithome30\Tests;

use Mockery;
use PHPUnit\Framework\TestCase;
use Recca0120\Ithome30\PttCrawler;
use Recca0120\Ithome30\Crawlers\Home;
use Recca0120\Ithome30\Crawlers\Board;

class PttCrawlerTest extends TestCase
{
    public function test_fetch_board_page()
    {
        /** @var Mockery\Mock|Home $home */
        $home = Mockery::mock(Home::class);
        $home->allows('all')->andReturn([[
            'name' => 'Gossiping',
            "nuser" => '8803',
            'class' => '綜合',
            'title' => '[八卦] 亞運李智凱、許皓鋐奪金!',
            'url' => 'https://www.ptt.cc/bbs/Gossiping/index.html'
        ]]);

        /** @var Mockery\Mock|Board $board */
        $board = Mockery::mock(Board::class);
        // 因為 fetch 回傳 Generator 所以我們必須用 andReturnUsing + Closure 來模擬回傳值
        $board->allows('fetch')->andReturnUsing(function () {
            yield [
                'board_name' => 'Gossiping',
                'board_class' => '綜合',
                'nrec' => '4',
                'type' => '問卦',
                'title' => '司機夫人真的有去卡地亞血拚$1.1M嗎?',
                'author' => 'uwmtsa',
                'date' => '10/06',
                'url' => 'https://www.ptt.cc/bbs/Gossiping/M.1696537444.A.1A5.html',
            ];
        });

        $crawler = new PttCrawler($home, $board);
        $records = $crawler->all();

        self::assertEquals([
            'board_name' => 'Gossiping',
            'board_class' => '綜合',
            'nrec' => '4',
            'type' => '問卦',
            'title' => '司機夫人真的有去卡地亞血拚$1.1M嗎?',
            'author' => 'uwmtsa',
            'date' => '10/06',
            'url' => 'https://www.ptt.cc/bbs/Gossiping/M.1696537444.A.1A5.html',
        ], $records[0]);
    }
}

接著再執行測試,如果得到紅燈就再去調整 PttCrawler 的程式碼,如果得到綠燈則表示程式碼正確!


上一篇
Day 24. 判斷測試的種類 - 把測試移到合適的地方
下一篇
Day 26. 兩個物件互動測試 - 變更 Mock 對象讓測試更穩固
系列文
開心撰寫 PHPUnit30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言